{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1af0a894-ec28-48f1-89a0-ca5b39d2abe1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import abc\n",
    "class AbstractFactory(object):  #The abstract factory\n",
    "   \n",
    "    __metaclass__ = abc.ABCMeta\n",
    "    def __init__(self):\n",
    "        self.product_function() \n",
    "\n",
    "    @abc.abstractmethod\n",
    "    def product_function(self):\n",
    "        pass\n",
    "\n",
    "class CGA_Factory1(AbstractFactory):   #CGAfactory\n",
    "    def product_function(self):\n",
    "        return sin1_function()\n",
    "\n",
    "class CGA_Factory3(AbstractFactory):   #CGAfactory\n",
    "    def product_function(self):\n",
    "        return ben_function()    \n",
    "\n",
    "\n",
    "class CGA_Factory2(AbstractFactory):   #The second factory has new value put in\n",
    "    def product_function(self):\n",
    "        return transfer_function()\n",
    "\n",
    "class model_Factory1(AbstractFactory):   # Source domain model\n",
    "    def product_function(self):\n",
    "        return model()\n",
    "    \n",
    "class model_Factory2(AbstractFactory):   # Target domain model\n",
    "    def product_function(self):\n",
    "        return model2()\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "adcf65af-5cfb-493e-8d3d-8294dfdc7418",
   "metadata": {},
   "outputs": [],
   "source": [
    "def translateDNA(pop):\n",
    "    return (pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2**DNA_SIZE-1) * (X_BOUND[1]+1) )-1 \n",
    "\n",
    "def select(pop, fitness):\n",
    "    idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,p=fitness/fitness.sum())\n",
    "    return pop[idx]\n",
    "\n",
    "def crossover(parent, pop):     # mating process (genes crossover)\n",
    "    if np.random.rand() < CROSS_RATE: \n",
    "        i_ = np.random.randint(0, POP_SIZE, size=1)                          \n",
    "        cross_points = np.random.randint(0, 2, size=DNA_SIZE).astype(np.bool) \n",
    "        parent[cross_points] = pop[i_, cross_points]\n",
    "    return parent\n",
    "\n",
    "def mutate(child):\n",
    "    for point in range(DNA_SIZE):\n",
    "        if np.random.rand() < MUTATION_RATE:\n",
    "            child[point] = 1 if child[point] == 0 else 0\n",
    "    return child\n",
    "\n",
    "def best(pop,fitness):\n",
    "    min_x=np.argmin(fitness)\n",
    "    best=pop[min_x]\n",
    "    tmp= np.random.randint(0, POP_SIZE, size=1)\n",
    "    pop[tmp]=best\n",
    "    \n",
    "def decodeDNA(x):\n",
    "    return (((x+1)/(X_BOUND[1]+1))*float(2**DNA_SIZE-1))  #To normalize to a decimal integer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "8de9cb67-11a0-4ab8-876d-a4d761896783",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import random\n",
    "%matplotlib inline\n",
    "import time\n",
    "import pandas as pd\n",
    "from itertools import chain\n",
    "Dim=1\n",
    "DNA_SIZE = 20            # DNA length\n",
    "POP_SIZE = 100           # population size\n",
    "CROSS_RATE = 0.8         # mating probability (DNA crossover)\n",
    "MUTATION_RATE = 0.003    # mutation probability\n",
    "X_BOUND = [-1, 2]         # x upper and lower bounds\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a7690e1a-464e-4388-b51a-d29dced463e1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([100, 1])\n",
      "torch.Size([100, 2])\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-13-75cfca8e404e>:22: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n",
      "  X=torch.tensor(X,dtype=torch.float)\n",
      "<ipython-input-13-75cfca8e404e>:23: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n",
      "  Y=torch.tensor(Y,dtype=torch.float)\n",
      "<ipython-input-13-75cfca8e404e>:27: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n",
      "  dataset=TensorDataset(torch.tensor(X,dtype=torch.float),torch.tensor(Y,dtype=torch.float))\n"
     ]
    }
   ],
   "source": [
    "import torch.nn as nn\n",
    "from torch.utils.data import DataLoader\n",
    "from torch.utils.data import TensorDataset\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import torch\n",
    "import time\n",
    "from itertools import chain\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "k=1\n",
    "x=pd.read_table('MIGA%sorder_x.txt'%(k),header = None) \n",
    "yy=pd.read_table('MIGA%sorder_fx.txt'%(k),header = None) \n",
    "z=pd.read_table('MIGA%sorder_z.txt'%(k),header = None) \n",
    "y=None\n",
    "y=np.hstack((yy,z))  # Merge y and z\n",
    "p=len(x)\n",
    "X= x.astype(float)\n",
    "Y= y.astype(float)\n",
    "X=torch.as_tensor(X.values.reshape(p,1))\n",
    "Y=torch.as_tensor(Y.reshape(p,2))\n",
    "X=torch.tensor(X,dtype=torch.float)\n",
    "Y=torch.tensor(Y,dtype=torch.float)\n",
    "print(X.size())\n",
    "print(Y.size())\n",
    "# Use batch training\n",
    "dataset=TensorDataset(torch.tensor(X,dtype=torch.float),torch.tensor(Y,dtype=torch.float))\n",
    "dataloader=DataLoader(dataset,batch_size=100,shuffle=True)\n",
    "class Net(nn.Module):  \n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.net=nn.Sequential(\n",
    "        nn.Linear(in_features=1,out_features=10),nn.ReLU(),\n",
    "        nn.Linear(10,100),nn.ReLU(),\n",
    "        nn.Linear(100,10),nn.ReLU(),\n",
    "        nn.Linear(10,2)\n",
    "    )\n",
    "\n",
    "    def forward(self, input:torch.FloatTensor):\n",
    "        output=self.net(input)[:,0].detach().numpy() \n",
    "        tmp=np.argmax(output) \n",
    "        self.net(input)[:,1]=X[tmp] \n",
    "        return self.net(input)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "cca48e28-20ef-4fc0-ba44-f563cdf19f1e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Model training\n",
    "class model(object): \n",
    "    def __repr__(self):\n",
    "\n",
    "        net=Net()\n",
    "        optim=torch.optim.Adam(Net.parameters(net),lr=0.001)\n",
    "        Loss=nn.MSELoss()\n",
    "        \n",
    "        print(\"Begin---\")\n",
    "        for epoch in range(14000):\n",
    "            loss=None \n",
    "            for batch_x,batch_y in dataloader: \n",
    "                y_predict=net(batch_x)  #Two values\n",
    "                loss=Loss(y_predict,batch_y)  \n",
    "                optim.zero_grad()\n",
    "                loss.backward()  \n",
    "                optim.step()\n",
    "\n",
    "            if (epoch+1)%200==0:\n",
    "                print(\"step: {0} , loss: {1}\".format(epoch+1,loss.item()))\n",
    "\n",
    "        predict=net(torch.tensor(X,dtype=torch.float))\n",
    "        torch.save(net.state_dict(), \"MIGA model parameters.pth\")\n",
    "        plt.plot(x,y[:,0],'b+',label=\"labeled data from EA\")\n",
    "        predict=predict.detach().numpy()\n",
    "        plt.plot(x,predict[:,0],'r.',label=\"predicted data from model\")\n",
    "        plt.xlabel(\"x\")\n",
    "        plt.ylabel(\"f(x,1)\")\n",
    "        plt.legend()\n",
    "        #plt.savefig(fname=\"Training %s_order models.png\"%(k),figsize=[10,10])\n",
    "        plt.show()\n",
    "        idx=np.argmin(predict[:,0])  \n",
    "        print(idx)\n",
    "        print(\"x：\",X[idx])\n",
    "        print(\"fx：\",predict[idx],\"---The second data is ignored\")\n",
    "        return "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b46f27ef-7285-49b7-bb60-2588b4877a98",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Training source model\n",
    "k=1\n",
    "m1=model_Factory1().product_function()\n",
    "print(m1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "780ad576-3101-4c91-a808-34549e426bc1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.nn import init\n",
    "import matplotlib\n",
    "%matplotlib inline\n",
    "import torch\n",
    "import time\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "matplotlib.rcParams['axes.unicode_minus']=False\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "class model2(object): \n",
    "    def __repr__(self):\n",
    "        net=Net()\n",
    "        for m in net.net.modules(): \n",
    "             if isinstance(m, nn.Linear):\n",
    "                param_shape = m.weight.shape\n",
    "                m.weight.data = torch.from_numpy(np.random.normal(0, 0.5, size=param_shape))  \n",
    "                m.weight.data=m.weight.data.float()\n",
    "        print(net.net[6].bias)\n",
    "        net.net[6].bias.data.zero_()\n",
    "        init.xavier_uniform_(net.net[6].weight,1) \n",
    "        pre_dict=torch.load('MIGA model parameters.pth')\n",
    "        model_dict=net.state_dict() \n",
    "        pre_dict =  {name: value for name, value in pre_dict.items() if name in model_dict} \n",
    "        model_dict.update(pre_dict) \n",
    "        net.load_state_dict(model_dict)\n",
    "        optim=torch.optim.Adam(Net.parameters(net),lr=0.001)\n",
    "        Loss=nn.MSELoss()\n",
    "        x=pd.read_table('MIGA%sorder_x.txt'%k,header = None) \n",
    "        yy=pd.read_table('MIGA%sorder_fx.txt'%k,header = None) \n",
    "        z=pd.read_table('MIGA%sorder_z.txt'%k,header = None) \n",
    "        y=None\n",
    "        y=np.hstack((yy,z))  \n",
    "        p=len(x)\n",
    "        X= x.astype(float)\n",
    "        Y= y.astype(float)\n",
    "        X=torch.as_tensor(X.values.reshape(p,1)) \n",
    "        Y=torch.as_tensor(Y.reshape(p,2))\n",
    "        X=torch.tensor(X,dtype=torch.float)\n",
    "        Y=torch.tensor(Y,dtype=torch.float)\n",
    "        p=len(x)\n",
    "        #print(p)\n",
    "        X=(x)\n",
    "        Y=(y)\n",
    "        X= X.astype(float)\n",
    "        Y= Y.astype(float)\n",
    "        X=torch.as_tensor(X.values.reshape(p,1))\n",
    "        Y=torch.as_tensor(Y.reshape(p,2))\n",
    "\n",
    "        dataset=TensorDataset(torch.tensor(X,dtype=torch.float),torch.tensor(Y,dtype=torch.float))\n",
    "        dataloader=DataLoader(dataset,batch_size=100,shuffle=True)\n",
    "\n",
    "        print(\"Begin!---\")\n",
    "        for epoch in range(20):\n",
    "            loss=None\n",
    "            for batch_x,batch_y in dataloader:\n",
    "                y_predict=net(batch_x)\n",
    "                loss=Loss(y_predict,batch_y) \n",
    "                optim.zero_grad()\n",
    "                loss.backward()\n",
    "                optim.step()\n",
    "            if (epoch+1)%1==0:\n",
    "                print(\"step: {0} , loss: {1}\".format(epoch+1,loss.item()))\n",
    "\n",
    "        predict=net(torch.tensor(X,dtype=torch.float))\n",
    "        #plt.plot(x,y[:,0],'b+',label=\"labeled data from EA\")\n",
    "        predict=predict.detach().numpy()\n",
    "        #plt.plot(x,predict[:,0],'r.',label=\"predicted data from model\")\n",
    "        #plt.xlabel(\"x\")\n",
    "        #plt.ylabel(\"f(x,265)\")\n",
    "        #plt.legend()\n",
    "        #plt.savefig(fname=\"Migration of the 265-order model.png\",figsize=[10,10])\n",
    "        #plt.show()\n",
    "        idx=np.argmin(predict[:,0]) \n",
    "        print(idx)\n",
    "        print(\"x：\",X[idx])\n",
    "        print(\"fx：\",predict[idx],\"---The second data is ignored\")\n",
    "        np.savetxt(\"best_x_we want.txt\",X[idx])   \n",
    "        \n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "09520546-49fc-4666-a975-fe49c009d86b",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Generate sin model of order 265\n",
    "k=265\n",
    "m2=model_Factory2().product_function()\n",
    "print(m2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43b4d245-7c26-4686-85e6-d0ed4d37d38a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e9ddc866-3bce-4a94-8e63-dfa140c591e3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
